package interpreter;

import grammar.FunParser;
import org.antlr.v4.runtime.tree.ParseTree;

import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;

public class Function {
    private String name;
    private int argumentCount;
    private ParseTree code;
    private Map<String, Integer> argumentNames = new TreeMap<String, Integer>();
    private Map<Integer, String> argumentNumbers = new TreeMap<Integer, String>();
    private TestFunVisitor visitor;

    public Function(FunParser.LetContext ctx, TestFunVisitor visitor) {

        // parse function name
        this.name = ctx.IDENTIFIER().getText();
        // parse argument names
        ParseTree lambda;
        lambda = ctx.lambda();
        //String debug=declaration.getChild(1).toString();

        String debug = lambda.getText();
        if (!lambda.getChild(1).getText().equals("()")) {
            int i = 1;
            while (!lambda.getChild(i).toString().equals("->")) {
                this.argumentNames.put(lambda.getChild(i).getText(), i - 1);
                this.argumentNumbers.put(i - 1, lambda.getChild(i).getText());
                ++i;
            }
            if (this.argumentNames.size() == i - 1) {
                this.argumentCount = this.argumentNames.size();
            } else {
                System.err.println("Two or more function arguments have same names!");
            }
            this.code = lambda.getChild(i);
        }

        this.code = lambda.getChild(lambda.getChildCount() - 1);
        this.visitor = visitor;
    }

    public Integer call(ArrayList<Integer> args) {
        System.err.print("function call name = " + name + " arguments: ");
        if (args != null) {
            for (Integer arg : args) {
                System.err.print(arg + " ");
            }
            System.err.println("");

            // prepare stack page
            Map<String, Integer> arguments = new TreeMap<String, Integer>();
            for (int i = 0; i < args.size(); i++) {
                arguments.put(this.getName() + "." + argumentNumbers.get(i), args.get(i));
            }

            StackPage stackPage = new StackPage(this.getName(), arguments);
            visitor.addStackPage(stackPage);
            // call function
            Integer result = visitor.visit(code);

            // clear stack

            visitor.removeStackPage();
            return result;
        }
        return visitor.visit(code);


    }

    public String getName() {
        return this.name;
    }

    public int getArgumentCount() {
        return argumentCount;
    }

    public Integer getElementByName(String argumentName) {
        return 0;
    }
}
